//
// Created by kode.zhong on 2021/3/14.
//

#ifndef LOX_VM_LOX_COMPILER_H_
#define LOX_VM_LOX_COMPILER_H_

#include <string>
#include <memory>

#include "chunk.h"
#include "scanner.h"

namespace lox {

struct Parser {
  Token current;
  Token previous;
  bool had_error;
  bool panic_mode;
};

class Compiler {
 public:
  template<class T>
  bool Compile(const std::string &source, std::shared_ptr<Chunk<T>> chunk_sp);
  void Compile(const std::string &source);
  void Advance(Scanner &scanner);
  void Consume(Scanner &scanner, TokenType type, const std::string &msg);
 private:
  Parser m_parser;
  void ErrorAtCurrent(const std::string &msg);
  void Error(const std::string &msg);
  void ErrorAt(Token &token, const std::string &msg);
  template<class T>
  void EmitByte(ChunkPtr<T> chunk_sp, uint8_t byte) {
    chunk_sp->WriteChunk(byte, m_parser.previous.line);
  }

  template<class T>
  void EmitReturn(ChunkPtr<T> chunk_sp) {
    EmitByte(chunk_sp, OP_RETURN);
  }

  template<class T>
  void EmitBytes(ChunkPtr<T> chunk_sp, uint8_t byte1, uint8_t byte2) {
    EmitByte(chunk_sp, byte1);
    EmitByte(chunk_sp, byte2);
  }

  template<class T>
  void EndCompile(ChunkPtr<T> chunk_sp);

  void Expression();
};

template<class T>
bool Compiler::Compile(const std::string &source, ChunkPtr<T> chunk_sp) {
  Scanner scanner{source};
  Advance(scanner);
  // Expression
  Consume(scanner, TOKEN_EOF, "Exptect end of expression.");
  EndCompile(chunk_sp);
  return !m_parser.had_error;
}

template<class T>
void Compiler::EndCompile(ChunkPtr<T> chunk_sp) {
  EmitReturn(chunk_sp);
}

}

#endif //LOX_VM_LOX_COMPILER_H_
